﻿using System;
using System.Collections.Generic;
using System.Linq;
using AviationMath;
using WeatherData;

namespace ATCAssistant
{
    static class RunwayCalculator
    {
        public static IEnumerable<RunwayRecommendation> RecommendedRunways(Station station)
        {
            ICollection<RunwayRecommendation> sortedRunways = new List<RunwayRecommendation>();
            Metar wxData = station.GetCurrentMetar();

            // Return an empty collection if we don't have records
            if (!wxData.Available)
                return sortedRunways;

            foreach (Runway rwy in station.Runways)
            {
                double hwind = E6bOperations.HeadwindComponent(rwy.Heading, wxData.WindDirection, wxData.WindSpeed);
                if (!RunwayIsUsable(station.Restrictions, hwind, rwy.Identifier))
                    continue;


                double xwind = E6bOperations.CrosswindComponent(rwy.Heading, wxData.WindDirection, wxData.WindSpeed);
                
                RunwayRecommendation rec = new RunwayRecommendation();                
                rec.Crosswind = Math.Abs(xwind);
                rec.Direction = CalculateCrosswindDirection(xwind);
                rec.Headwind = hwind;
                rec.Runway = rwy;
                rec.Score = rec.Crosswind > 0 ? rec.Headwind / rec.Crosswind : rec.Headwind;

                sortedRunways.Add(rec);
            }

            return sortedRunways.OrderByDescending(rec => rec.Score);
        }

        private static bool RunwayIsUsable(List<Restriction> restrictions, double headwind, string runwayId)
        {
            List<Restriction> currentRestrictions = restrictions.FindAll(rest => rest.RunwayId.Equals(runwayId));
            foreach (Restriction rest in currentRestrictions)
            {
                // Closed runways are not usable
                if (rest.Status == RestrictionStatus.Closed)
                    return false;

                // Check for time-restricted runways
                if (TimeOfDayIsBetween(rest.StartTime, rest.StopTime) && rest.Status != RestrictionStatus.Available)
                    return false;
            }

            // Runways with a tailwind are not usable
            if (headwind < -3)
                return false;

            // This runway passed all disqualifying tests
            return true;
        }
        private static bool TimeOfDayIsBetween(TimeSpan startTime, TimeSpan endTime)
        {
            DateTime time = DateTime.Now;
            if (endTime == startTime)
            {
                return true;
            }
            else if (endTime < startTime)
            {
                return time.TimeOfDay <= endTime || time.TimeOfDay >= startTime;
            }
            else
            {
                return time.TimeOfDay >= startTime && time.TimeOfDay <= endTime;
            }
        }
        private static CrosswindDirection CalculateCrosswindDirection(double xwind)
        {
            if (xwind == 0)
                return CrosswindDirection.None;
            else if (xwind < 0)
                return CrosswindDirection.Left;
            else
                return CrosswindDirection.Right;
        } 
    }
}
